/**
 * 
 */
package com.finalist.util;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;

import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.command.BinaryCommandFactory;
import net.rubyeye.xmemcached.exception.MemcachedException;
import net.rubyeye.xmemcached.utils.AddrUtil;

import org.apache.log4j.Logger;

import com.google.code.yanf4j.core.impl.StandardSocketOption;

/**
 * XMemcached是一个基于Java nio的memcached客户端。
 * 它线程安全，结构简单，支持所有的memcached文本协议和二进制协议，并且有比较优异的性能表现。
 * 它还支持一些高级特性，如JMX、动态增删节点、客户端统计以及nio连接池
 * @author pengyb
 *
 */
public class XMemCachedUtils
{
    protected static Logger logger = Logger.getLogger(XMemCachedUtils.class);

    // 创建全局的唯一实例
    protected static MemcachedClient memcache = null;

    //    protected static MemCachedUtils memCached = new MemCachedUtils();

    // 设置与缓存服务器的连接池
    static
    {
        String cacheAddress = ConstConfigUtil.getString("memcache.address", "shopxx");

        MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses(cacheAddress), new int[] { 1 });
        // 服务器列表和其权重
        //        String[] servers = { "127.0.0.1:11211" }; //这个端口是memcache服务的端口号
        //        Integer[] weights = { 3 };
        // socke连接池
        //设置连接池大小.推荐在0-30之间
        builder.setConnectionPoolSize(30);

        //设置失败模式
        builder.setFailureMode(true);

        //使用二进制文件
        builder.setCommandFactory(new BinaryCommandFactory());

        //默认如果连接超过5秒没有任何IO操作发生即认为空闲并发起心跳检测
        builder.getConfiguration().setSessionIdleTimeout(10000); // 设置为10秒;

        //数据较小，如在1K以下，默认的配置选项已经足够。如果数据较大，推荐调整网络层的TCP选项，如设置socket的接收和发送缓冲区更大，启用Nagle算法等等：   
        builder.setSocketOption(StandardSocketOption.SO_RCVBUF, 32 * 1024);// 设置接收缓存区为32K，默认16K
        builder.setSocketOption(StandardSocketOption.SO_SNDBUF, 16 * 1024); // 设置发送缓冲区为16K，默认为8K
        builder.setSocketOption(StandardSocketOption.TCP_NODELAY, false); // 启用nagle算法，提高吞吐量，默认关闭

        //网络层的优化
        //默认采用阻塞读，在局域网内能带来更好的效率，可以设置网络参数，linux系统在多节点memcached下，
        //强烈建议将读线程数设置大于0，接近或者等于memcached节点数（具体参数看你的测试结果）；在windows系统，推荐采用默认设置(也就是单线程）：
        //        builder.setBufferAllocator(new CachedBufferAllocator());
        //采用CachedBufferAllocator    
        builder.getConfiguration().setReadThreadCount(10); // 设置读线程数   

        //如上面代码所示，你可以采用CachedBufferAllocator作为ByteBuffer的分配器，
        //这个分配器将在ThreadLocal中缓存创建的ByteBuffer重复利用，使用此分配器经测试没有带来显著的性能提升，慎用。

        //memcache.setEnableHeartBeat这个关闭，仅仅是关闭了心跳的功能，客户端仍然会去统计连接是否空闲，禁止统计可以通过：
        builder.getConfiguration().setStatisticsServer(false);

        try
        {
            memcache = builder.build();

            //Xmemcached默认会做两个优化：将连续的单个get合并成一个multi get批量操作获取，将连续的请求合并成socket发送缓冲区大小的buffer发送。
            //如果对响应时间比较在意，那么可以将合并的因子减小，或者关闭合并buffer的优化：
            //如果对吞吐量更在意，那么也可将合并因子调大，默认是150。但是也不可太大，太大可能导致平均响应时间延长

            memcache.setMergeFactor(50); //默认是150，缩小到50

            //get优化默认是开启的，可以通过夏明惊喜关闭
            //memcache.setOptimizeGet(false);//默认是true，推荐使用true

            memcache.setOptimizeMergeBuffer(false); //关闭合并buffer的优化

            //如果对心跳检测不在意，也可以关闭心跳检测，减小系统开销
            memcache.setEnableHeartBeat(false);

            //由于xmemcached的通讯层是基于非阻塞IO的，那么在请求发送给memcached之后，需要等待应答的到来，这个等待时间默认是1秒，
            //如果 超过1秒就抛出java.util.TimeoutExpcetion给用户。如果频繁抛出此异常，可以尝试将全局的等待时间设置长一些，在这里设置为5秒：
            memcache.setOpTimeout(10000L);//全局的等待时间

        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 合并数据，如果数据不存在则保存一条新的，存在则修改
     * @param key  数据key值
     * @param value 数据value
     * @return
     * @throws TimeoutException
     * @throws InterruptedException
     * @throws MemcachedException
     */
    public static boolean merge(String key, Object value)
    {
        try
        {
            return memcache.set(key, 0, value);

        }
        catch (TimeoutException e)
        {
            logger.error("连接membercache服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        catch (InterruptedException e)
        {
            logger.error("连接membercache服务阻塞异常或者服务终止,错误信息: 【" + e.getMessage() + "】");
        }
        catch (MemcachedException e)
        {
            logger.error("membercache合并数据(merge)服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        return false;
    }

    /**
     * 合并数据,并设置数据失效时间，如果数据不存在则保存一条新的，存在则修改
     * @param key
     * @param exp
     * @param value
     * @return
     * @throws TimeoutException
     * @throws InterruptedException
     * @throws MemcachedException
     */
    public static boolean merge(String key, int exp, Object value)
    {
        try
        {
            return memcache.set(key, exp, value);
        }
        catch (TimeoutException e)
        {
            logger.error("连接membercache服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        catch (InterruptedException e)
        {
            logger.error("连接membercache服务阻塞异常或者服务终止,错误信息: 【" + e.getMessage() + "】");
        }
        catch (MemcachedException e)
        {
            logger.error("membercache保存数据(merge)服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        return false;
    }

    /**
     * 保存数据
     * @param key
     * @param value
     * @return
     * @throws TimeoutException
     * @throws InterruptedException
     * @throws MemcachedException
     */
    public static boolean save(String key, Object value)
    {
        try
        {
            return memcache.add(key, 0, value);
        }
        catch (TimeoutException e)
        {
            logger.error("连接membercache服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        catch (InterruptedException e)
        {
            logger.error("连接membercache服务阻塞异常或者服务终止,错误信息: 【" + e.getMessage() + "】");
        }
        catch (MemcachedException e)
        {
            logger.error("membercache保存数据(save)服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        return false;
    }

    /**
     * 保存数据，并设置失效时间
     * @param key
     * @param exp
     * @param value
     * @return
     * @throws TimeoutException
     * @throws InterruptedException
     * @throws MemcachedException
     */
    public static boolean save(String key, int exp, Object value) throws TimeoutException, InterruptedException, MemcachedException
    {
        try
        {
            return memcache.add(key, exp, value);
        }
        catch (TimeoutException e)
        {
            logger.error("连接membercache服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        catch (InterruptedException e)
        {
            logger.error("连接membercache服务阻塞异常或者服务终止,错误信息: 【" + e.getMessage() + "】");
        }
        catch (MemcachedException e)
        {
            logger.error("membercache保存数据(save)服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        return false;
    }

    /**
     * 修改数据
     * @param key
     * @param value
     * @return
     * @throws TimeoutException
     * @throws InterruptedException
     * @throws MemcachedException
     */
    public static boolean update(String key, Object value) throws TimeoutException, InterruptedException, MemcachedException
    {
        try
        {
            return memcache.replace(key, 0, value);
        }
        catch (TimeoutException e)
        {
            logger.error("连接membercache服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        catch (InterruptedException e)
        {
            logger.error("连接membercache服务阻塞异常或者服务终止,错误信息: 【" + e.getMessage() + "】");
        }
        catch (MemcachedException e)
        {
            logger.error("membercache保存数据(save)服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        return false;
    }

    /**
     * 修改数据，并设置失效时间
     * @param key
     * @param exp
     * @param value
     * @return
     * @throws TimeoutException
     * @throws InterruptedException
     * @throws MemcachedException
     */
    public static boolean update(String key, int exp, Object value)
    {
        try
        {
            return memcache.replace(key, exp, value);
        }
        catch (TimeoutException e)
        {
            logger.error("连接membercache服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        catch (InterruptedException e)
        {
            logger.error("连接membercache服务阻塞异常或者服务终止,错误信息: 【" + e.getMessage() + "】");
        }
        catch (MemcachedException e)
        {
            logger.error("membercache修改数据(update)服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        return false;
    }

    /**
     * 
     * @param key
     * @return
     * @throws TimeoutException
     * @throws InterruptedException
     * @throws MemcachedException
     */
    public static Object get(String key)
    {
        try
        {
            return memcache.get(key);
        }
        catch (TimeoutException e)
        {
            logger.error("连接membercache服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        catch (InterruptedException e)
        {
            logger.error("连接membercache服务阻塞异常或者服务终止,错误信息: 【" + e.getMessage() + "】");
        }
        catch (MemcachedException e)
        {
            logger.error("membercache获取数据(get)服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        return null;
    }

    /**
     * 删除数据
     * @param key 
     * @return
     * @throws TimeoutException
     * @throws InterruptedException
     * @throws MemcachedException
     */
    public static boolean delete(String key)
    {
        try
        {
            return memcache.delete(key);
        }
        catch (TimeoutException e)
        {
            logger.error("连接membercache服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        catch (InterruptedException e)
        {
            logger.error("连接membercache服务阻塞异常或者服务终止,错误信息: 【" + e.getMessage() + "】");
        }
        catch (MemcachedException e)
        {
            logger.error("membercache删除数据(delete)服务超时,错误信息: 【" + e.getMessage() + "】");
        }
        return false;
    }

    /**
     * 
     * @param args
     * @throws MemcachedException 
     * @throws InterruptedException 
     * @throws TimeoutException 
     */
    public static void main(String[] args) throws TimeoutException, InterruptedException, MemcachedException
    {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("key", "123");
        XMemCachedUtils.merge("hello", map);
        System.out.print("get value : " + XMemCachedUtils.get("hello"));
        Map<String, Object> map1 = (Map<String, Object>) XMemCachedUtils.get("hello");
        System.out.println(map1);
        //
        //        System.out.print("get value : " + MemCachedUtils.update("hello", "ok"));
    }
}
